package com.ruoyi.server;

import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.server.netty.MyLengthFieldBasedFrameDecoder;
import com.ruoyi.server.netty.NettyServerHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.net.InetSocketAddress;

/**
 * @author: ReWinD00
 * @date: 2021-07-05 10:42
 */
@Component
@Slf4j
public class NettyServer extends Thread {

    public static String MsgCode = "GBK";

    @Value("${server.netty.port}")
    public Integer port;

    //发送的数据帧最大长度
    private static final int maxFrameLength = Integer.MAX_VALUE;
    //定义长度域位于发送的字节数组中的下标
    private static final int lengthFieldOffset = 16;
    //用于描述定义的长度域的长度默认只支持 1, 2, 3, 4, or 8（原版）
    //我这里重写了解码器，所以支持传入任意长度
    private static final int lengthFieldLength = 2;
    //偏移位，即：长度字节和内容中间隔了几个字节
    private static final int lengthAdjustment = 0;
    //表示获取完一个完整的数据包之后，忽略前面的几个字节
    private static final int initialBytesToStrip = 6;

    @Override
    public void run() {
        startServer();
    }

    private void startServer() {
        EventLoopGroup bossGroup = null;
        EventLoopGroup workGroup = null;
        ServerBootstrap serverBootstrap = null;
        ChannelFuture future = null;
        try {
            //初始化线程组
            bossGroup = new NioEventLoopGroup();
            workGroup = new NioEventLoopGroup();
            //初始化服务端配置
            serverBootstrap = new ServerBootstrap();
            //绑定线程组
            serverBootstrap.group(bossGroup, workGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch)
                                throws Exception {
                            ch.pipeline().addLast("decoder", new MyLengthFieldBasedFrameDecoder(2048, 16, 2, 0, 0));
                            ch.pipeline().addLast(SpringUtils.getBean(NettyServerHandler.class));
                        }
                    }).option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);
            future = serverBootstrap.bind(new InetSocketAddress(port)).sync();
            log.info(" *************TCP服务端启动成功 Port：{}*********** ", port);
        } catch (Exception e) {
            log.error("TCP服务端启动异常", e);
        } finally {
            if (future != null) {
                try {
                    future.channel().closeFuture().sync();
                } catch (InterruptedException e) {
                    log.error("channel关闭异常：", e);
                }
            }
            if (bossGroup != null) {
                //线程组资源回收
                bossGroup.shutdownGracefully();
            }

            if (workGroup != null) {
                //线程组资源回收
                workGroup.shutdownGracefully();
            }


        }
    }

}